package com.eshop.tools.service.impl;

import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ScheduledThreadPoolExecutor;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import com.eshop.exception.BadRequestException;
import cn.hutool.extra.template.Template;
import cn.hutool.extra.template.TemplateEngine;
import java.util.Collections;
import java.util.Map;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.extra.template.TemplateUtil;
import cn.hutool.extra.template.TemplateConfig;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.eshop.tools.domain.vo.EmailVo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Service;
import com.eshop.tools.service.VerificationCodeService;
import com.eshop.tools.domain.VerificationCode;
import com.eshop.tools.service.mapper.VerificationCodeMapper;
import com.eshop.common.service.impl.BaseServiceImpl;

@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = { Exception.class })
public class VerificationCodeServiceImpl extends BaseServiceImpl<VerificationCodeMapper, VerificationCode> implements VerificationCodeService
{
    @Value("${code.expiration}")
    private Integer expiration;
    
    @Transactional(rollbackFor = { Exception.class })
    public EmailVo sendEmail(final VerificationCode code) {
        final VerificationCode verificationCode = this.getOne((Wrapper)((Wrappers.<VerificationCode>lambdaQuery().eq(VerificationCode::getScenes, code.getScenes())).eq(VerificationCode::getType, code.getType())).eq(VerificationCode::getValue, code.getValue()));
        final TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("template", TemplateConfig.ResourceMode.CLASSPATH));
        final Template template = engine.getTemplate("email/email.ftl");
        EmailVo emailVo;
        if (verificationCode == null) {
            code.setCode(RandomUtil.randomNumbers(6));
            final String content = template.render((Map)Dict.create().set("code", code.getCode()));
            emailVo = new EmailVo(Collections.singletonList(code.getValue()), "yshop后台管理系统", content);
            this.save(code);
            this.timedDestruction(code);
        }
        else {
            final String content = template.render((Map)Dict.create().set("code", verificationCode.getCode()));
            emailVo = new EmailVo(Collections.singletonList(verificationCode.getValue()), "yshop后台管理系统", content);
        }
        return emailVo;
    }
    
    public void validated(final VerificationCode code) {
        final VerificationCode verificationCode = this.getOne((Wrapper)(((Wrappers.<VerificationCode>lambdaQuery().eq(VerificationCode::getScenes, code.getScenes())).eq(VerificationCode::getType, code.getType())).eq(VerificationCode::getValue, code.getValue())).eq(VerificationCode::getStatus, true));
        if (verificationCode == null || !verificationCode.getCode().equals(code.getCode())) {
            throw new BadRequestException("无效验证码");
        }
        verificationCode.setStatus(false);
        this.save(verificationCode);
    }
    
    private void timedDestruction(final VerificationCode verifyCode) {
        final ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, (ThreadFactory)new BasicThreadFactory.Builder().namingPattern("verifyCode-schedule-pool-%d").daemon(true).build());
        try {
            executorService.schedule(() -> {
                verifyCode.setStatus(false);
                this.save(verifyCode);
            }, this.expiration * 60 * 1000L, TimeUnit.MILLISECONDS);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}
